
package com.shop.cloud.mall.api.controller;

import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.shop.cloud.common.core.constant.CacheConstants;
import com.shop.cloud.common.core.constant.CommonConstants;
import com.shop.cloud.common.core.constant.SecurityConstants;
import com.shop.cloud.common.core.util.R;
import com.shop.cloud.common.portal.annotation.ApiLogin;
import com.shop.cloud.common.portal.constant.PortalConstants;
import com.shop.cloud.common.portal.constant.PortalReturnCode;
import com.shop.cloud.common.portal.interceptor.ThirdSessionInterceptor;
import com.shop.cloud.common.portal.util.ApiUtil;
import com.shop.cloud.mall.api.service.CouponUserService;
import com.shop.cloud.mall.api.service.UserInfoService;
import com.shop.cloud.common.portal.util.ThirdSessionHolder;
import com.shop.cloud.mall.common.constant.MallConstants;
import com.shop.cloud.mall.common.dto.UserInfoLoginDTO;
import com.shop.cloud.mall.common.entity.CouponUser;
import com.shop.cloud.mall.common.entity.UserInfo;
import com.shop.cloud.weixin.common.feign.FeignWxUserService;
import com.shop.cloud.weixin.common.dto.WxOpenDataDTO;
import com.shop.cloud.common.portal.entity.ThirdSession;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.concurrent.CompletableFuture;

/**
 * 商城用户
 *
 * @author
 * @date 2019-12-04 11:09:55
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/userinfo")
@Tag(description = "userinfo", name = "商城用户API")
public class UserInfoController {

    private final UserInfoService userInfoService;
	private final CouponUserService couponUserService;
	private final FeignWxUserService feignWxUserService;
	private final RedisTemplate redisTemplate;
	private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();

	/**
	 * 查询商城用户
	 * @return R
	 */
	@Operation(summary = "查询商城用户")
    @GetMapping
	@ApiLogin
    public R getById() {
		UserInfo userInfo = new UserInfo();
		userInfo.setId(ThirdSessionHolder.getUserId());
		long couponNum = couponUserService.count(Wrappers.<CouponUser>lambdaQuery()
				.eq(CouponUser :: getUserId, userInfo.getId())
				.eq(CouponUser :: getStatus, CommonConstants.NO)
				.gt(CouponUser :: getValidEndTime, LocalDateTime.now()));
		userInfo = userInfoService.getById(userInfo.getId());
		if(userInfo != null){
			userInfo.setCouponNum((int)couponNum);
		}
        return R.ok(userInfo);
    }

	/**
	 * 通过微信小程序更新用户信息
	 * @param wxOpenDataDTO
	 * @return
	 */
	@Operation(summary = "通过微信小程序更新用户信息")
	@PutMapping("/ma")
	@ApiLogin
	public R updateByMa(@RequestBody WxOpenDataDTO wxOpenDataDTO){
		ThirdSession thirdSession = ThirdSessionHolder.getThirdSession();
		wxOpenDataDTO.setAppId(thirdSession.getAppId());
		wxOpenDataDTO.setUserId(thirdSession.getWxUserId());
		wxOpenDataDTO.setSessionKey(thirdSession.getSessionKey());
		return R.ok(userInfoService.updateByMa(wxOpenDataDTO));
	}

	/**
	 * 通过微信公众号网页授权更新用户信息
	 * @param wxOpenDataDTO
	 * @return
	 */
	@Operation(summary = "通过微信公众号网页授权更新用户信息")
	@PutMapping("/mp")
	@ApiLogin
	public R updateByMp(@RequestBody WxOpenDataDTO wxOpenDataDTO){
		ThirdSession thirdSession = ThirdSessionHolder.getThirdSession();
		wxOpenDataDTO.setAppId(thirdSession.getAppId());
		wxOpenDataDTO.setUserId(thirdSession.getWxUserId());
		return R.ok(userInfoService.updateByMp(wxOpenDataDTO));
	}

	/**
	 * 通过小程序授权手机号一键登录商城
	 * @param wxOpenDataDTO
	 * @return
	 */
	@Operation(summary = "通过小程序授权手机号一键登录商城")
	@PostMapping("/ma/phone/login")
	public R loginByPhoneMa(HttpServletRequest request, @RequestBody WxOpenDataDTO wxOpenDataDTO){
		//获取thirdSession
		ThirdSession thirdSession = ThirdSessionHolder.getThirdSession();
		String thirdSessionHeader = request.getHeader(PortalConstants.HEADER_THIRDSESSION);
		String key = ThirdSessionInterceptor.getSessionRedisKey(thirdSessionHeader);
		wxOpenDataDTO.setSessionKey(thirdSession.getSessionKey());
		wxOpenDataDTO.setAppId(ApiUtil.getAppId(request));
		//解密获取手机号
		R<WxMaPhoneNumberInfo> r = feignWxUserService.getPhoneNumber(wxOpenDataDTO, SecurityConstants.FROM_IN);
		if(!r.isOk()){
			throw new RuntimeException(r.getMsg());
		}
		WxMaPhoneNumberInfo wxMaPhoneNumberInfo = r.getData();
		String phone = wxMaPhoneNumberInfo.getPhoneNumber();
		//通过手机号登录
		UserInfo userInfo = userInfoService.loginByPhoneWx(thirdSession,phone,key,wxOpenDataDTO.getSharerUserCode());
		//异步更新用户省市
		if(userInfo != null && StrUtil.isNotEmpty(userInfo.getId())){
			CompletableFuture.runAsync(() -> {
				userInfoService.updateProCity(request, userInfo.getId());
			});
		}
		return R.ok(userInfo);
	}

	/**
	 * 手机验证码登录
	 * @param userInfoLoginDTO
	 * @return
	 */
	@Operation(summary = "手机验证码登录")
	@PostMapping("/phone/login")
	public R loginByPhone(HttpServletRequest request, @RequestBody UserInfoLoginDTO userInfoLoginDTO){
		//核实验证码
		String key = CacheConstants.VER_CODE_DEFAULT + CommonConstants.PHONE_CODE_1 + ":" + userInfoLoginDTO.getPhone();
		Object codeObj = redisTemplate.opsForValue().get(key);
		if (codeObj == null) {
			return R.failed(PortalReturnCode.ERR_60009.getCode(), PortalReturnCode.ERR_60009.getMsg());
		}
		String saveCode = codeObj.toString();
		if (!StrUtil.equals(saveCode, userInfoLoginDTO.getCode())) {
			return R.failed(PortalReturnCode.ERR_60009.getCode(), PortalReturnCode.ERR_60009.getMsg());
		}
		UserInfo userInfo = userInfoService.loginByPhone(request,userInfoLoginDTO);
		//异步更新用户省市
		if(userInfo != null && StrUtil.isNotEmpty(userInfo.getId())){
			CompletableFuture.runAsync(() -> {
				userInfoService.updateProCity(request, userInfo.getId());
			});
		}
		return R.ok(userInfo);
	}

	/**
	 * 账号登录
	 * @param userInfoLoginDTO
	 * @return
	 */
	@Operation(summary = "账号登录")
	@PostMapping("/login")
	public R login(HttpServletRequest request, @RequestBody UserInfoLoginDTO userInfoLoginDTO){
		//通过手机号登录
		UserInfo userInfo = userInfoService.getOne(Wrappers.<UserInfo>query().lambda()
				.eq(UserInfo::getPhone, userInfoLoginDTO.getPhone()));
		if(userInfo == null){
			return R.failed(PortalReturnCode.ERR_60007.getCode(), PortalReturnCode.ERR_60007.getMsg());
		}
		//校验账号密码
		if(StrUtil.isBlank(userInfo.getPassword()) ||
				!ENCODER.matches(userInfoLoginDTO.getPassword(),userInfo.getPassword())){
			return R.failed(PortalReturnCode.ERR_60010.getCode(), PortalReturnCode.ERR_60010.getMsg());
		}
		//登录
		userInfo = userInfoService.login(request,userInfo);
		//异步更新用户省市
		if(userInfo != null && StrUtil.isNotEmpty(userInfo.getId())){
			UserInfo finalUserInfo = userInfo;
			CompletableFuture.runAsync(() -> {
				userInfoService.updateProCity(request, finalUserInfo.getId());
			});
		}
		//分销关系上级绑定，用户类型 1、老用户
		userInfo.setSharerUserCode(userInfoLoginDTO.getSharerUserCode());
		userInfoService.parentBind(MallConstants.DISTRIBUTION_USER_TYPE_1,userInfo);
		return R.ok(userInfo);
	}

	/**
	 * 退出登录
	 * @param request
	 * @return
	 */
	@Operation(summary = "退出登录")
	@PostMapping("/logout")
	public R logout(HttpServletRequest request){
		UserInfo userInfo = userInfoService.logout(request);
		return R.ok(userInfo);
	}

	/**
	 * 注册或重置账号
	 * @param userInfoLoginDTO
	 * @return
	 */
	@Operation(summary = "注册或重置账号")
	@PostMapping("/register")
	public R register(HttpServletRequest request, @RequestBody UserInfoLoginDTO userInfoLoginDTO){
		//判断手机号是否已经注册
		UserInfo userInfo = userInfoService.getOne(Wrappers.<UserInfo>query().lambda()
				.eq(UserInfo::getPhone, userInfoLoginDTO.getPhone()));
		//核实验证码
		String key;
		if(userInfo != null) {//重置密码
			key = CacheConstants.VER_CODE_DEFAULT + CommonConstants.PHONE_CODE_4 + ":" + userInfoLoginDTO.getPhone();
		}else{
			key = CacheConstants.VER_CODE_DEFAULT + CommonConstants.PHONE_CODE_2 + ":" + userInfoLoginDTO.getPhone();
		}
		Object codeObj = redisTemplate.opsForValue().get(key);
		if (codeObj == null) {
			return R.failed(PortalReturnCode.ERR_60009.getCode(), PortalReturnCode.ERR_60009.getMsg());
		}
		String saveCode = codeObj.toString();
		if (!StrUtil.equals(saveCode, userInfoLoginDTO.getCode())) {
			return R.failed(PortalReturnCode.ERR_60009.getCode(), PortalReturnCode.ERR_60009.getMsg());
		}
		//判断手机号是否已经注册
		if(userInfo != null){//重置密码
			userInfo.setPassword(ENCODER.encode(userInfoLoginDTO.getPassword()));
			userInfoService.updateById(userInfo);
			return R.ok(userInfo);
		}else{
			userInfo = new UserInfo();
		}
		//注册账号
		userInfo.setAppType(ApiUtil.getClientType(request));
		userInfo.setAppId(ApiUtil.getAppId(request));
		userInfo.setPhone(userInfoLoginDTO.getPhone());
		userInfo.setPassword(userInfoLoginDTO.getPassword());
		userInfo = userInfoService.register(userInfo);
		//分销关系上级绑定，用户类型 1、老用户
		userInfo.setSharerUserCode(userInfoLoginDTO.getSharerUserCode());
		userInfoService.parentBind(MallConstants.DISTRIBUTION_USER_TYPE_2,userInfo);
		redisTemplate.delete(key);
		return R.ok(userInfo);
	}

	/**
	 * 修改商城用户
	 * @param userInfo 商城用户
	 * @return R
	 */
	@Operation(summary = "修改商城用户")
	@PutMapping
	@ApiLogin
	public R updateById(@RequestBody UserInfo userInfo) {
		userInfo.setUserCode(null);
		userInfo.setPhone(null);
		userInfo.setPassword(null);
		userInfo.setUserGrade(null);
		userInfo.setParentId(null);
		return R.ok(userInfoService.updateById(userInfo));
	}

	/**
	 * 修改商城用户手机号
	 * @param userInfoLoginDTO
	 * @return R
	 */
	@Operation(summary = "修改商城用户手机号")
	@PostMapping("/phone")
	@ApiLogin
	public R updatePhone(@RequestBody UserInfoLoginDTO userInfoLoginDTO) {
		//核实验证码
		String key = CacheConstants.VER_CODE_DEFAULT + CommonConstants.PHONE_CODE_2 + ":" + userInfoLoginDTO.getPhone();
		Object codeObj = redisTemplate.opsForValue().get(key);
		if (codeObj == null) {
			return R.failed(PortalReturnCode.ERR_60009.getCode(), PortalReturnCode.ERR_60009.getMsg());
		}
		String saveCode = codeObj.toString();
		if (!StrUtil.equals(saveCode, userInfoLoginDTO.getCode())) {
			return R.failed(PortalReturnCode.ERR_60009.getCode(), PortalReturnCode.ERR_60009.getMsg());
		}
		UserInfo userInfo = new UserInfo();
		userInfo.setId(ThirdSessionHolder.getUserId());
		userInfo.setPhone(userInfoLoginDTO.getPhone());
		return R.ok(userInfoService.updateById(userInfo));
	}

	/**
	 * 分页查询
	 * @param page 分页对象
	 * @param userInfo 商城用户
	 * @return
	 */
	@Operation(summary = "推广人列表")
	@GetMapping("/page")
	@ApiLogin
	public R getUserinfoPage(Page page, UserInfo userInfo) {
		return R.ok(userInfoService.page1(page, userInfo));
	}

}
